package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.cache.CategoryCache;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.client.search.SearchClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.entity.dto.QuestionFormDTO;
import com.tianji.learning.entity.po.InteractionQuestion;
import com.tianji.learning.entity.po.InteractionReply;
import com.tianji.learning.entity.query.QuestionAdminPageQuery;
import com.tianji.learning.entity.query.QuestionPageQuery;
import com.tianji.learning.entity.vo.QuestionAdminVO;
import com.tianji.learning.entity.vo.QuestionVO;
import com.tianji.learning.enums.QuestionStatus;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.service.IInteractionQuestionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.service.IInteractionReplyService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * <p>
 * 互动提问的问题表 服务实现类
 * </p>
 *
 * @author lemon
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class InteractionQuestionServiceImpl extends ServiceImpl<InteractionQuestionMapper, InteractionQuestion> implements IInteractionQuestionService {

    private final UserClient userClient;

    private final IInteractionReplyService interactionReplyService;

    private final CatalogueClient catalogueClient;

    private final SearchClient searchClient;

    private final CourseClient courseClient;

    private final CategoryCache categoryCache;

    /**
     * 新增互动问题
     *
     * @param dto
     */
    @Override
    public void addInteractionQuestion(QuestionFormDTO dto) {
        // 1.获取当前登录用户Id
        Long userId = UserContext.getUser();
        // 2.dto转po
        InteractionQuestion interactionQuestion = BeanUtils.copyBean(dto, InteractionQuestion.class);
        // 2.1.设置用户Id
        interactionQuestion.setUserId(userId);
        // 默认隐藏是显示

        // 3.保存
        this.save(interactionQuestion);

    }

    /**
     * 修改互动问题
     *
     * @param id
     * @param dto
     */
    @Override
    public void updateInteractionQuestion(Long id, QuestionFormDTO dto) {

        // 校验
        // 1.校验问题是否存在
        if (StringUtils.isBlank(dto.getTitle()) || StringUtils.isBlank(dto.getDescription()) || dto.getAnonymity() == null) {
            throw new BadRequestException("非法参数");
        }
        // 校验id
        InteractionQuestion question = this.getById(id);
        if (question == null) {
            throw new BadRequestException("问题不存在");
        }
        // 1.获取当前登录用户Id
        Long userId = UserContext.getUser();
        // 并且修改只能修改自己的
        Long userId1 = question.getUserId();

        if (!userId.equals(userId1)) {
            throw new BadRequestException("不能修改别人的问题");
        }

        // 2.dto转po
        question.setAnonymity(dto.getAnonymity());
        question.setTitle(dto.getTitle());
        question.setDescription(dto.getDescription());

        // 3.更新
        this.updateById(question);
    }

    /**
     * 用户端分页查询问题
     *
     * @param query
     * @return
     */
    @Override
    public PageDTO<QuestionVO> queryQuestionPage(QuestionPageQuery query) {
        // 1、校验 courseId
        if (query.getCourseId() == null) {
            throw new BadRequestException("课程id不能为空");
        }

        // 2.获取当前登录用户Id
        Long userId = UserContext.getUser();

        // 3.分页查询 interaction_question
        // courseId 只有在onlyMine为true才加上
        // 小节id不为null才加上
        // 并且hidden为false
        // 按照提问时间倒序
        Page<InteractionQuestion> page = this.lambdaQuery()
                // TODO 使用mybatis-plus实现不查询某个字段 简写
                .select(InteractionQuestion.class,  c -> !c.getProperty().equals("description"))
                .select(InteractionQuestion.class, new Predicate<TableFieldInfo>() {
                    @Override
                    public boolean test(TableFieldInfo tableFieldInfo) {
                        // tableFieldInfo.getProperty() // 获取InteractionQuestion的属性名
                        return !tableFieldInfo.getProperty().equals("description");
                    }
                })
                .eq(InteractionQuestion::getCourseId, query.getCourseId())
                .eq(query.getOnlyMine() != null, InteractionQuestion::getUserId, userId)
                .eq(query.getSectionId() != null, InteractionQuestion::getSectionId, query.getSectionId())
                .eq(InteractionQuestion::getHidden, false)
                .page(query.toMpPage("create_time", false));
        List<InteractionQuestion> records = page.getRecords();
        if (CollUtils.isEmpty(records)) {
            // 返回空的PageDTO
            return PageDTO.empty(page);
        }
        // 下面就不是空的了

        //
        // 转为Set 可以去重
        Set<Long> lastAnswerQuestionId = records.stream().map(InteractionQuestion::getLatestAnswerId).filter(latestAnswerId -> latestAnswerId != null).collect(Collectors.toSet());
        Set<Long> userIds = new HashSet<>();

        // 根据最新回答id 批量查询
        // 并且转为Map
        Map<Long, InteractionReply> interactionReplyMap = new HashMap<>();
        List<InteractionReply> interactionReplies = new ArrayList<>();
        if (CollUtils.isNotEmpty(lastAnswerQuestionId)) {
            //interactionReplies = interactionReplyService.listByIds(lastAnswerQuestionId);
            // 这里就不能使用主键了 还需要没有被隐藏的
            interactionReplies = interactionReplyService.list(new LambdaQueryWrapper<InteractionReply>()
                    .eq(InteractionReply::getHidden, false)
                    .in(InteractionReply::getId, lastAnswerQuestionId));
            if (CollUtils.isNotEmpty(interactionReplies)) {
                for (InteractionReply interactionReply : interactionReplies) {
                    if (!interactionReply.getAnonymity()) {
                        // 这个是回复的用户的id 并且不是匿名的  因为匿名的话就不显示名字，并且回答的内容是在interaction_reply表里面
                        userIds.add(interactionReply.getUserId());
                    }
                    // 这里你就使用普通的
                    interactionReplyMap.put(interactionReply.getId(), interactionReply);
                }
//                interactionReplyMap = interactionReplies.stream().collect(Collectors.toMap(InteractionReply::getId, item -> item));
            }
        }

        // 5.查询用户信息
        // 5.1.获取所有的用户id
        // 并且只查询不匿名的
        // 但是我们还需要将匿名的用户信息也返回
        // 因此我们的UserIds还需要加上匿名的用户id
        /*userIds = records.stream().filter(item -> !item.getAnonymity()).map(InteractionQuestion::getUserId).collect(Collectors.toSet());
        for (InteractionReply interactionReply : interactionReplies) {
            if (!interactionReply.getAnonymity()) {
                // 这个是回复的用户的id 并且不是匿名的  因为匿名的话就不显示名字，并且回答的内容是在interaction_reply表里面
                userIds.add(interactionReply.getUserId());
            }
        }*/
        for (InteractionQuestion question : records) {
            if (!question.getAnonymity()) {
                // 如果这个记录不是匿名的话，那么就将这个用户id加入到userIds中
                // 注意他不是回复的用户id
                userIds.add(question.getUserId());
            }
        }

        // 5.2.批量查询用户信息
        List<UserDTO> userDTOS = userClient.queryUserByIds(userIds);

        // 5.3.转为Map
        Map<Long, UserDTO> userDTOMap = new HashMap<>();
        if (CollUtils.isNotEmpty(userDTOS)) {
            // 这里还是使用普通的
            for (UserDTO userDTO : userDTOS) {
                userDTOMap.put(userDTO.getId(), userDTO);
            }
//            userDTOMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, item -> item));
        }


        // 6.vo返回
        List<QuestionVO> collect = records.stream().map(item -> {
            QuestionVO vo = BeanUtils.copyBean(item, QuestionVO.class);

            if (!vo.getAnonymity()) {
                // 5.查询用户信息
                if (userDTOMap.get(vo.getUserId()) != null) {
                    vo.setUserName(userDTOMap.get(vo.getUserId()).getName());
                    vo.setUserIcon(userDTOMap.get(vo.getUserId()).getIcon());
                }

            }

            // 回答的内容
            Long latestAnswerId = item.getLatestAnswerId();
            if (interactionReplyMap.get(latestAnswerId) != null) {
                // 最新回答如果是非匿名的话，才显示
                if (!interactionReplyMap.get(latestAnswerId).getAnonymity()) {
                    // 去interaction_reply表查询最新的回复
                    // 最新回复人的名称，注意匿名 TODO
                    // 获取到对象里面的userId 然后再去user中查询
                    if (userDTOMap.get(interactionReplyMap.get(latestAnswerId).getUserId()) != null) {
                        vo.setLatestReplyUser(userDTOMap.get(interactionReplyMap.get(latestAnswerId).getUserId()).getName());
                    }
                }
                vo.setLatestReplyContent(interactionReplyMap.get(latestAnswerId).getContent());
            }
            return vo;
        }).collect(Collectors.toList());
        // 最后返回
        return PageDTO.of(page, collect);
    }

    /**
     * 回显互动问题
     *
     * @param id
     * @return
     */
    @Override
    public QuestionVO getInteractionQuestion(Long id) {
        // 1.根据id查询数据
        InteractionQuestion question = getById(id);
        // 2.数据校验
        if (question == null || question.getHidden()) {
            // 没有数据或者是被隐藏了
            return null;
        }
        // 3.查询提问者信息
        UserDTO user = null;
        if (!question.getAnonymity()) {
            user = userClient.queryUserById(question.getUserId());
        }
        // 4.封装VO
        QuestionVO vo = BeanUtils.copyBean(question, QuestionVO.class);
        if (user != null) {
            vo.setUserName(user.getName());
            vo.setUserIcon(user.getIcon());
        }
        return vo;
    }

    /**
     * 删除互动问题
     *
     * @param id
     */
    @Override
    public void removeInteractionQuestion(Long id) {

        // 判断是不是自己
        Long userId = UserContext.getUser();

        InteractionQuestion question = this.getById(id);
        if (question == null) {
            throw new BizIllegalException("互动问题不存在");
        }
        if (!question.getUserId().equals(userId)) {
            throw new BizIllegalException("只能删除自己的互动问题");
        }

        // 删除互动问题
        this.removeById(id);

        // 删除互动回复
        interactionReplyService.remove(new LambdaQueryWrapper<InteractionReply>()
                .eq(InteractionReply::getQuestionId, id));
    }

    /**
     * 隐藏显示互动问题
     *
     * @param id
     * @param hidden
     */
    @Override
    public void hiddenQuestion(Long id, Boolean hidden) {
        // 先查询
        InteractionQuestion question = this.getById(id);
        if (question == null) {
            throw new BizIllegalException("互动问题不存在");
        }
        question.setHidden(hidden);
        this.updateById(question);
    }

    @Transactional
    @Override
    public QuestionAdminVO queryQuestionDetail(Long id) {
        // 查询互动问题
        InteractionQuestion question = this.getById(id);
        if (question == null) {
            throw new BizIllegalException("互动问题不存在");
        }
        question.setStatus(QuestionStatus.CHECKED);
        // 修改
        this.updateById(question);

        // 封装vo
        QuestionAdminVO questionAdminVO = BeanUtils.copyBean(question, QuestionAdminVO.class);


        Long chapterId = question.getChapterId();
        Long sectionId = question.getSectionId();
        // 查询章节信息
        Set<Long> chapterIds = new HashSet<>();
        chapterIds.add(chapterId);
        chapterIds.add(sectionId);
        List<CataSimpleInfoDTO> cataSimpleInfoDTOS = catalogueClient.batchQueryCatalogue(chapterIds);
        if (CollUtils.isEmpty(cataSimpleInfoDTOS)) {
            throw new BizIllegalException("章节信息不存在");
        }
        // 封装为map
        Map<Long, CataSimpleInfoDTO> cataSimpleInfoDTOMap = cataSimpleInfoDTOS.stream().collect(Collectors.toMap(CataSimpleInfoDTO::getId, item -> item));


        questionAdminVO.setStatus(QuestionStatus.CHECKED.getValue());
        if (cataSimpleInfoDTOMap.get(question.getChapterId()) != null) {
            questionAdminVO.setChapterName(cataSimpleInfoDTOMap.get(question.getChapterId()).getName() == null ? "" : cataSimpleInfoDTOMap.get(question.getChapterId()).getName());
        }
        if (cataSimpleInfoDTOMap.get(question.getSectionId()) != null) {
            questionAdminVO.setSectionName(cataSimpleInfoDTOMap.get(question.getSectionId()).getName() == null ? "" : cataSimpleInfoDTOMap.get(question.getSectionId()).getName());
        }

        // 根据courseId查询
        CourseFullInfoDTO courseInfoById = courseClient.getCourseInfoById(question.getCourseId(), false, false);
        if (courseInfoById == null) {
            throw new BizIllegalException("课程信息不存在");
        }
        questionAdminVO.setCourseName(courseInfoById.getName());

        // 查询三级分类
        List<Long> categoryIds = courseInfoById.getCategoryIds();
        String categoryNameList = categoryCache.getCategoryNames(categoryIds);
        questionAdminVO.setCategoryName(categoryNameList);

        // 查询用户信息 和 教师信息
        List<Long> teacherIds = courseInfoById.getTeacherIds();
        // 设置教师名称
        if (teacherIds == null) {
            teacherIds = new ArrayList<>();
        }

        teacherIds.add(question.getUserId());
        List<UserDTO> userDTOS = userClient.queryUserByIds(teacherIds);
        if (CollUtils.isEmpty(userDTOS)) {
            throw new BizIllegalException("用户信息不存在");
        }
        Map<Long, UserDTO> userDTOMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, item -> item));
        if (userDTOMap.get(question.getUserId()) != null) {
            questionAdminVO.setUserName(userDTOMap.get(question.getUserId()).getName() == null ? "" : userDTOMap.get(question.getUserId()).getName());
        }
        // 将教师名称拼接按照逗号分隔
        List<String> teacherNameList = new ArrayList<>();
        for (Long teacherId : teacherIds) {
            if (userDTOMap.get(teacherId) != null) {
                teacherNameList.add(userDTOMap.get(teacherId).getName() == null ? "" : userDTOMap.get(teacherId).getName());
            }
        }
        questionAdminVO.setTeacherName(org.apache.commons.lang3.StringUtils.join(teacherNameList, ","));
        return questionAdminVO;
    }

    /**
     * 分页查询问题列表-管理端
     *
     * @param query
     * @return
     */
    @Override
    public PageDTO<QuestionAdminVO> queryQuestionPageForAdmin(QuestionAdminPageQuery query) {

        // 如果用户传递了课程名称， 则从es中获取该名称对应的课程id
        List<Long> courseIds = null;
        if (StringUtils.isNotBlank(query.getCourseName())) {
            courseIds = searchClient.queryCoursesIdByName(query.getCourseName());
            // 没有就直接返回null
            if (CollUtils.isEmpty(courseIds)) {
                return PageDTO.empty(0L, 0L);
            }
        }

        // 查询全部的互动问题  条件就是动态sql
        Page<InteractionQuestion> page = this.lambdaQuery()
                .eq(query.getStatus() != null, InteractionQuestion::getStatus, query.getStatus())
                // 传了课程名称，就需要根据课程名称查询
                .in(StringUtils.isNotBlank(query.getCourseName()), InteractionQuestion::getCourseId, courseIds)
                .gt(query.getBeginTime() != null, InteractionQuestion::getCreateTime, query.getBeginTime())
                .lt(query.getEndTime() != null, InteractionQuestion::getCreateTime, query.getEndTime())
                //
                //.between(query.getBeginTime() != null && query.getEndTime() != null, InteractionQuestion::getCreateTime, query.getBeginTime(), query.getEndTime())
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        List<InteractionQuestion> records = page.getRecords();
        // 返回空的
        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(page);
        }

        // 远程调用获取用户信息

        // 1.获取所有的用户id
        // 直接是所有
        Set<Long> userIdSet = records.stream().map(InteractionQuestion::getUserId).collect(Collectors.toSet());

        // 2.批量查询用户信息
        List<UserDTO> userDTOS = userClient.queryUserByIds(userIdSet);
        // 3.转为map
        Map<Long, UserDTO> userDTOMap = new HashMap<>();
        if (CollUtils.isEmpty(userDTOS)) {
            // 没有用户信息
            throw new BizIllegalException("用户信息不存在");
        }
        // 这里还是使用普通的
        for (UserDTO userDTO : userDTOS) {
            userDTOMap.put(userDTO.getId(), userDTO);
        }

        // 远程调用获取课程信息
        Set<Long> courseIdSet = records.stream().map(InteractionQuestion::getCourseId).collect(Collectors.toSet());
        List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(courseIdSet);
        Map<Long, CourseSimpleInfoDTO> simpleInfoMap = new HashMap<>();
        if (CollUtils.isEmpty(simpleInfoList)) {
            throw new BizIllegalException("课程信息不存在");
        }
        for (CourseSimpleInfoDTO simpleInfoDTO : simpleInfoList) {
            // 转为map
            simpleInfoMap.put(simpleInfoDTO.getId(), simpleInfoDTO);
        }


        // 远程调用获取章节信息
        // 收集章节和小节的id
        Set<Long> sectionIdSet = new HashSet<>();
        for (InteractionQuestion record : records) {
            sectionIdSet.add(record.getSectionId());
            sectionIdSet.add(record.getChapterId());
        }

        List<CataSimpleInfoDTO> cataSimpleInfoDTOS = catalogueClient.batchQueryCatalogue(sectionIdSet);
        Map<Long, CataSimpleInfoDTO> cataSimpleInfoDTOMap = new HashMap<>();
        if (CollUtils.isEmpty(cataSimpleInfoDTOS)) {
            throw new BizIllegalException("章节信息不存在");
        }
        for (CataSimpleInfoDTO cataSimpleInfoDTO : cataSimpleInfoDTOS) {
            cataSimpleInfoDTOMap.put(cataSimpleInfoDTO.getId(), cataSimpleInfoDTO);
        }

        List<QuestionAdminVO> adminVOS = new ArrayList<>();
        for (InteractionQuestion record : records) {
            QuestionAdminVO questionAdminVO = BeanUtils.copyBean(record, QuestionAdminVO.class);
            UserDTO userDTO = userDTOMap.get(record.getUserId());
            if (userDTO != null) {
                questionAdminVO.setUserName(userDTO.getName());
            }
            CourseSimpleInfoDTO simpleInfoDTO = simpleInfoMap.get(record.getCourseId());
            if (simpleInfoDTO != null) {
                questionAdminVO.setCourseName(simpleInfoDTO.getName() == null ? "" : simpleInfoDTO.getName());
                List<Long> categoryIds = simpleInfoDTO.getCategoryIds(); // 一二三级分类id
                String categoryNames = categoryCache.getCategoryNames(categoryIds);
                // 设置分类名称
                questionAdminVO.setCategoryName(categoryNames); // 三级分类
            }
            // 设置章节和小节的名称
            CataSimpleInfoDTO chapter = cataSimpleInfoDTOMap.get(record.getChapterId());
            if (chapter != null) {
                questionAdminVO.setChapterName(chapter.getName() == null ? "" : chapter.getName());
            }
            CataSimpleInfoDTO section = cataSimpleInfoDTOMap.get(record.getSectionId());
            if (section != null) {
                // 设置小节名称
                questionAdminVO.setSectionName(section.getName() == null ? "" : section.getName());
            }

            adminVOS.add(questionAdminVO);
        }

        return PageDTO.of(page, adminVOS);
    }
}
